package com.changgou.seckill.task;

import com.alibaba.fastjson.JSON;
import com.changgou.entity.IdWorker;
import com.changgou.entity.SystemConstants;
import com.changgou.seckill.dao.SeckillGoodsMapper;
import com.changgou.seckill.pojo.SeckillGoods;
import com.changgou.seckill.pojo.SeckillOrder;
import com.changgou.seckill.pojo.SeckillStatus;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * Created by zhangyuhong
 * Date:2020/5/23
 */
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
//注意:这里因为秒杀,要求速度大,所以暂不操作数据库,直接操作缓存,只有存货没有了才更新数据库
    //而且 用到了异步处理
@Component
public class MultiThreadingCreateOrder {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Async//异步的 本质就是多线程
    public void createOrder() {
        try {
            System.out.println("模拟下单开始================================:" + Thread.currentThread().getName());
            SeckillStatus seckillStatus = (SeckillStatus)redisTemplate.boundListOps(SystemConstants.SEC_KILL_USER_QUEUE_KEY).rightPop();
            if (seckillStatus != null) {
                Long id = seckillStatus.getGoodsId();
                String username = seckillStatus.getUsername();
                String time = seckillStatus.getTime();

                //获取商品数据
                SeckillGoods goods = (SeckillGoods) redisTemplate.boundHashOps(SystemConstants.SEC_KILL_GOODS_PREFIX + time).get(id);
               /* if (goods == null || goods.getStockCount() <= 0) {
                    throw new MyGoodsExecption("已售罄!");
                }*/
                //如果有库存，则创建秒杀商品订单
                SeckillOrder seckillOrder = new SeckillOrder();
                seckillOrder.setId(idWorker.nextId());  //点单id
                seckillOrder.setSeckillId(id);
                seckillOrder.setMoney(goods.getCostPrice());   //设置价格
                seckillOrder.setUserId(username);
                seckillOrder.setCreateTime(new Date());
                seckillOrder.setStatus("0");  //未支付
                //抢单成功
                //将秒杀订单存入到Redis中  //只能秒杀一个  如果是可以秒啥多个  那就存list
                redisTemplate.boundHashOps(SystemConstants.SEC_KILL_ORDER_KEY).put(username,seckillOrder);   //名字为key,秒杀订单为value
                //库存减少
//                goods.setStockCount(goods.getStockCount()-1);  //因为有分布式锁,在一进来就开始减少了
                //判断当前商品是否还有库存
                if (goods.getStockCount()<=0) {
                    //如果没有库存,则清空Redis缓存中该商品
                    redisTemplate.boundHashOps(SystemConstants.SEC_KILL_GOODS_PREFIX + time).delete(id);
                    //同步更新到 商品 的sql数据库中  没有了才才更新
                    seckillGoodsMapper.updateByPrimaryKeySelective(goods);
                }else {
                    //如果有库存，则将数据重置到订单 Reids中  这是预订单,暂时还不需要更新到数据库中,到时候支付成功后再更新到订单中
                    //修改这个订单的状态  由排队中  变成  等待支付
                    seckillStatus.setStatus(2);
                    seckillStatus.setOrderId(seckillOrder.getId());   //这样要传给支付页面,所以要这个值
                    seckillStatus.setMoney(Float.valueOf(seckillOrder.getMoney()));  //这样要传给支付页面,所以要这个值
                    redisTemplate.boundHashOps(SystemConstants.SEC_KILL_USER_STATUS_KEY).put(username, seckillStatus);
                    sendTimerMessage(seckillStatus);  //把状态发送到延迟消息队列里
                }
            }
            System.out.println("模拟下单开始================================:" + Thread.currentThread().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Autowired
    Environment environment;

    /***
     * 发送延时消息到RabbitMQ中
     * @param seckillStatus
     */
    public void sendTimerMessage(SeckillStatus seckillStatus){
        rabbitTemplate.convertAndSend(environment.getProperty("mq.pay.queue.seckillordertimerdelay"), (Object) JSON.toJSONString(seckillStatus), new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setExpiration("10000");  //延迟的时间
                return message;
            }
        });
    }
}
